/***
 * Copyright (c) 2021-2031 murenchao
 * fig is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *       http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */
package cool.taomu.software.fig.classloader

import java.lang.annotation.Documented
import java.lang.annotation.Retention
import java.lang.annotation.Target
import java.util.concurrent.ConcurrentSkipListMap

import static extension cool.taomu.software.fig.reflect.ReflectUtils.*

class FigClassLoaderManage {
    @Documented
    @Retention(RUNTIME)
    @Target(FIELD)
    annotation Autowired {
        Class<?> value = void;
        String name = "";
    }

    val static classes = new ConcurrentSkipListMap<String, FigClassLoader>();

    def void register(String name, byte[] bytes) {
        val classLoader = new FigClassLoader()
        classLoader.register(name, bytes);
        classes.put(name, classLoader);
    }

    def void register(Class<?> zlass, byte[] bytes) {
        val classLoader = new FigClassLoader()
        classLoader.register(zlass.name, bytes);
        classes.put(zlass.name, classLoader);
    }

    def void register(String name, Class<?> zlass) {
        val classLoader = new FigClassLoader()
        classLoader.register(name, zlass);
        classes.put(name, classLoader);
    }

    def getClassLoader(String name) {
        var classLoader = classes.get(name);
        if (classLoader === null) {
            var cl = Thread.currentThread.contextClassLoader.loadClass(name);
            return cl;
            //System.classLoader.loadClass(name);
        }
        return classLoader.loadClass(name);
    }

    def register(Class<?> zlass) {
        val classLoader = new FigClassLoader();
        classLoader.register(zlass);
        classes.put(zlass.name, classLoader);
    }

    def get(String key) {
        if (classes.containsKey(key)) {
            return classes.get(key);
        }
        return null;
    }

    def Object getBean(String className) {
        if (classes.containsKey(className)) {
            var zlass2 = this.getClassLoader(className);
            return getBean(zlass2);
        } else {
            var zlass = Thread.currentThread.contextClassLoader.loadClass(className);
            return getBean(zlass);
        }

    }

    def Object getBean(Class<?> key) {
        if (!classes.containsKey(key.name)) {
            register(key);
        }
        var zlass = this.getClassLoader(key.name);
        var instance = zlass.newInstance(null);
        var fields = zlass.getReflectFields();
        for (field : fields) {
            var autowired = field.getAnnotation(Autowired);
            if (autowired !== null) {
                if (!autowired.value.equals(void)) {
                    var fieldInstance = this.getBean(autowired.value);
                    zlass.setReflectFields(field.name, instance, fieldInstance);
                } else if (!autowired.name.equals("")) {
                    var fieldInstance = this.getBean(autowired.name);
                    zlass.setReflectFields(field.name, instance, fieldInstance);
                } else {
                    if (!field.type.isInterface) {
                        var fieldInstance = this.getBean(field.type);
                        zlass.setReflectFields(field.name, instance, fieldInstance);
                    }
                }
            }
        }
        return instance;
    }

}
